﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Net;
using System.Xml.Linq;
using System.Web;
using System.Windows;

namespace Reserve
{
    public enum ConfirmMode
    {
        ForceMode,
        SignalMode
    }

    public class AutoClickChecker
    {
        public static Dictionary<Thread, bool> StatusDic = new Dictionary<Thread, bool>();
        public static ManualResetEventSlim CheckDoor = new ManualResetEventSlim(false);

        public static void DoCheck()
        {
            AutoClickManager.InitialDoor.Wait();

            while (true)
            {
                Thread.Sleep(ConfigHelper.CheckerSleep);
                CheckContext checkContext = AutoClickManager.GetOneCheckContext();
                if (checkContext != null)
                {
                    while (true)
                    {
                        try
                        {
                            RequestContext context = new RequestContext();
                            context.RequestUrl = checkContext.Url;
                            context.AllowAutoRedirect = false;
                            context.Method = "POST";
                            context.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
                            context.ContentType = "application/x-www-form-urlencoded";
                            context.PostData = checkContext.PostData;
                            context.Headers.Add("Accept-Encoding", "gzip,deflate,sdch");
                            context.Headers.Add("Accept-Language", "en-US,en;q=0.8");
                            context.Headers.Add("Cookie", checkContext.Cookie);

                            ResponseContext response = Helper.GetResponse(context);
                            if (response.StatusCode != HttpStatusCode.OK)
                            {
                                throw new Exception();
                            }
                            bool isTimeout = Helper.CheckSessionTimeout(checkContext.Cookie, response.Headers.Get("set-cookie"));
                            if (isTimeout == true)
                            {
                                throw new TimeoutException();
                            }

                            bool productionAvailable = response.Content.Contains(ConfigHelper.CurrentProductionID);
                            lock (StatusDic)
                            {
                                StatusDic[Thread.CurrentThread] = productionAvailable;
                                if (productionAvailable == false)
                                {
                                    foreach (var item in StatusDic.Values)
                                    {
                                        if (item == true)
                                        {
                                            productionAvailable = true;
                                            break;
                                        }
                                    }
                                }

                                if (productionAvailable == true)
                                {
                                    if (CheckDoor.IsSet == false)
                                    {
                                        CheckDoor.Set();
                                    }
                                }
                                else
                                {
                                    if (CheckDoor.IsSet == true)
                                    {
                                        CheckDoor.Reset();
                                    }
                                }
                            }
                            break;
                        }
                        catch (Exception ex)
                        {
                            if (ex is TimeoutException)
                            {
                                break;
                            }
                        }
                    }
                }
                else
                {
                    Thread.Sleep(5000);
                }
            }
        }
    }

    public class AutoClickDatePicker
    {
        public static ManualResetEventSlim PickDateDoor = new ManualResetEventSlim(false);

        public static string[] TimeAndMark;

        private static string cookie = string.Empty;

        private static volatile bool isInvalidCookie = true;

        public static void DoPickDate()
        {
            AutoClickManager.InitialDoor.Wait();
            List<Thread> pickDateWorkers = new List<Thread>();

            try
            {
                while (true)
                {
                    Thread.Sleep(5000);
                    if (isInvalidCookie == true)
                    {
                        foreach (var item in pickDateWorkers)
                        {
                            item.Abort();
                        }
                        pickDateWorkers.Clear();

                        cookie = AutoClickManager.GetOneLoginedCookie();

                        if (cookie != string.Empty)
                        {
                            isInvalidCookie = false;

                            for (int i = 0; i < ConfigHelper.DatePicker; i++)
                            {
                                Thread pickDateWorker = new Thread(AutoClickDatePicker.DoPickDateWork);
                                pickDateWorkers.Add(pickDateWorker);
                                pickDateWorker.Start();
                            }
                        }
                    }
                }
            }
            finally
            {
                foreach (var item in pickDateWorkers)
                {
                    item.Abort();
                }
            }
        }

        private static void DoPickDateWork()
        {
            while (true)
            {
                if (TimeAndMark != null)
                {
                    Thread.Sleep(ConfigHelper.CheckerSleep);
                }
                try
                {
                    TimeAndMark = AutoClick.PickupDateStep(cookie);
                    if (PickDateDoor.IsSet == false)
                    {
                        PickDateDoor.Set();
                    }
                }
                catch (Exception ex)
                {
                    if (ex is TimeoutException)
                    {
                        isInvalidCookie = true;
                        break;
                    }
                }
            }
        }
    }

    public class CheckContext
    {
        public CheckContext(string cookie, string url, string postData)
        {
            Cookie = cookie;
            Url = url;
            PostData = postData;
        }

        public string Cookie { get; private set; }
        public string Url { get; private set; }
        public string PostData { get; private set; }
    }

    public class AutoClick
    {
        private const string selectStoreUrlTemp = @"http://reserve.apple.com/WebObjects/ProductReservation.woa/wa/reserveProduct?lang=en&country={0}&prelaunch={1}";
        private const string renderCartUrlTemp = @"http://reserve.apple.com/WebObjects/ProductReservation.woa/wa/GianduiaAction/renderCart?lang=en&country={0}";
        private const string createReservationUrlTemp = @"http://reserve.apple.com/WebObjects/ProductReservation.woa/wa/GianduiaAction/createReservation?lang=en&country={0}";
        private const string addToCartPostDataTemp = @"skuID={0}A&planID=null&lang=en&country={1}";

        public static int WaitingCheckDoorCount = 0;

        private ConfirmMode confirmMode;

        public AutoClick(ConfirmMode confirmMode)
        {
            this.confirmMode = confirmMode;
        }

        private string cookie = string.Empty;
        public string Cookie
        {
            get
            {
                return cookie;
            }
        }

        public CheckContext ContextForCheck { get; private set; }

        private string confirmPostData;
        private string confirmAction;

        private string InitialStep()
        {
            RequestContext context = new RequestContext();
            context.RequestUrl = string.Format(selectStoreUrlTemp, ConfigHelper.CurrentCountry, ConfigHelper.CurrentPrelaunchID);
            context.AllowAutoRedirect = false;
            context.Method = "GET";
            context.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
            context.Headers.Add("Accept-Encoding", "gzip,deflate,sdch");
            context.Headers.Add("Accept-Language", "en-US,en;q=0.8");
            context.Headers.Add("Cookie", "0");

            ResponseContext response = Helper.GetResponse(context);
            if (response.StatusCode != HttpStatusCode.OK)
            {
                throw new Exception();
            }
            if (response.Content.Contains("id=\"isCartEmpty\"") == false)
            {
                throw new TimeoutException();
            }

            string cookieString = response.Headers.Get("set-cookie");
            int index;
            index = cookieString.IndexOf("NSC_");
            string nscCookieName = cookieString.Substring(index, cookieString.IndexOf('=', index) - index);
            this.cookie = Helper.GetCookie(cookieString, new List<string>() { "RPRCookie", "wosid", "woinst", nscCookieName });

            return response.Content;
        }

        private string SelectStoreStep(string responseContent)
        {
            List<string> postDataIds = new List<string>() { "id=\"isCartEmpty\"", "id=\"productImage\"", "id=\"defaultStoreImage\"" };
            string selectStorePostData = string.Empty;
            int index;
            int beginIndex;
            string domHTML;
            XDocument dom;
            foreach (var item in postDataIds)
            {
                index = responseContent.IndexOf(item);
                while (responseContent[index] != '<')
                {
                    index--;
                }

                beginIndex = index;

                while (responseContent[index] != '>')
                {
                    index++;
                }

                domHTML = responseContent.Substring(beginIndex, index - beginIndex + 1);
                dom = XDocument.Parse(domHTML);
                selectStorePostData = selectStorePostData + dom.Root.Attribute("name").Value + "=" + HttpUtility.UrlEncode(dom.Root.Attribute("value").Value) + "&";
            }
            selectStorePostData = selectStorePostData + "storeNumber=" + ConfigHelper.CurrentStoreID;

            index = responseContent.IndexOf("id=\"TheForm\"");
            while (responseContent[index] != '<')
            {
                index--;
            }

            beginIndex = index;

            while (responseContent[index] != '>')
            {
                index++;
            }

            domHTML = responseContent.Substring(beginIndex, index - beginIndex) + "/>";
            dom = XDocument.Parse(domHTML);
            string selectStoreAction = "http://reserve.apple.com" + dom.Root.Attribute("action").Value;

            this.ContextForCheck = new CheckContext(this.cookie, selectStoreAction, selectStorePostData);

            RequestContext context = new RequestContext();
            context.RequestUrl = selectStoreAction;
            context.AllowAutoRedirect = false;
            context.Method = "POST";
            context.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
            context.ContentType = "application/x-www-form-urlencoded";
            context.PostData = selectStorePostData;
            context.Headers.Add("Accept-Encoding", "gzip,deflate,sdch");
            context.Headers.Add("Accept-Language", "en-US,en;q=0.8");
            context.Headers.Add("Cookie", this.cookie);

            ResponseContext response = Helper.GetResponse(context);
            if (response.StatusCode != HttpStatusCode.OK)
            {
                throw new Exception();
            }
            bool isTimeout = Helper.CheckSessionTimeout(this.cookie, response.Headers.Get("set-cookie"));
            if (isTimeout == true)
            {
                throw new TimeoutException();
            }

            return response.Content;
        }

        private void RenderCartStep()
        {
            RequestContext context = new RequestContext();
            context.RequestUrl = string.Format(renderCartUrlTemp, ConfigHelper.CurrentCountry);
            context.AllowAutoRedirect = false;
            context.Method = "POST";
            context.Accept = "*/*";
            context.PostData = null;
            context.Headers.Add("Accept-Encoding", "gzip,deflate,sdch");
            context.Headers.Add("Accept-Language", "en-US,en;q=0.8");
            context.Headers.Add("Cookie", this.cookie);

            ResponseContext response = Helper.GetResponse(context);
            if (response.StatusCode != HttpStatusCode.OK)
            {
                throw new Exception();
            }
            bool isTimeout = Helper.CheckSessionTimeout(this.cookie, response.Headers.Get("set-cookie"));
            if (isTimeout == true)
            {
                throw new TimeoutException();
            }
        }

        private void AddToCartStep()
        {
            RequestContext context = new RequestContext();
            context.RequestUrl = "http://reserve.apple.com/WebObjects/ProductReservation.woa/wa/GianduiaAction/addToCart";
            context.AllowAutoRedirect = false;
            context.Method = "POST";
            context.Accept = "*/*";
            context.ContentType = "application/x-www-form-urlencoded";
            context.PostData = string.Format(addToCartPostDataTemp, ConfigHelper.CurrentProductionID, ConfigHelper.CurrentCountry);
            context.Headers.Add("Accept-Encoding", "gzip,deflate,sdch");
            context.Headers.Add("Accept-Language", "en-US,en;q=0.8");
            context.Headers.Add("Cookie", this.cookie);

            ResponseContext response = Helper.GetResponse(context);
            if (response.StatusCode != HttpStatusCode.OK)
            {
                throw new Exception();
            }
            bool isTimeout = Helper.CheckSessionTimeout(this.cookie, response.Headers.Get("set-cookie"));
            if (isTimeout == true)
            {
                throw new TimeoutException();
            }
        }

        private string CreateReservationStep()
        {
            RequestContext context = new RequestContext();
            context.RequestUrl = string.Format(createReservationUrlTemp, ConfigHelper.CurrentCountry);
            context.AllowAutoRedirect = false;
            context.Method = "GET";
            context.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
            context.Headers.Add("Accept-Encoding", "gzip,deflate,sdch");
            context.Headers.Add("Accept-Language", "en-US,en;q=0.8");
            context.Headers.Add("Cookie", this.cookie);

            ResponseContext response = Helper.GetResponse(context);
            if (response.StatusCode != HttpStatusCode.Redirect || response.Headers.Get("location").Contains("/WebObjects/ProductReservation.woa/wo") == false)
            {
                if (response.StatusCode == HttpStatusCode.OK)
                {
                    bool isTimeoutForOK = Helper.CheckSessionTimeout(this.cookie, response.Headers.Get("set-cookie"));
                    if (isTimeoutForOK == true)
                    {
                        throw new TimeoutException();
                    }
                }
                throw new Exception();
            }

            bool isTimeout = Helper.CheckSessionTimeout(this.cookie, response.Headers.Get("set-cookie"));
            if (isTimeout == true)
            {
                throw new TimeoutException();
            }

            return response.Headers.Get("location");
        }

        private string CreateReservationRedirectStep(string redirectUrl)
        {
            RequestContext context = new RequestContext();
            context.RequestUrl = redirectUrl;
            context.AllowAutoRedirect = false;
            context.Method = "GET";
            context.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
            context.Headers.Add("Accept-Encoding", "gzip,deflate,sdch");
            context.Headers.Add("Accept-Language", "en-US,en;q=0.8");
            context.Headers.Add("Cookie", this.cookie);

            ResponseContext response = Helper.GetResponse(context);
            if (response.StatusCode != HttpStatusCode.OK)
            {
                throw new Exception();
            }
            bool isTimeout = Helper.CheckSessionTimeout(this.cookie, response.Headers.Get("set-cookie"));
            if (isTimeout == true)
            {
                throw new TimeoutException();
            }

            return response.Content;
        }

        private string LoginStep(string responseContent)
        {
            int index;
            int beginIndex;
            string domHTML;
            XDocument dom;

            index = responseContent.IndexOf("id=\"TheForm\"");
            while (responseContent[index] != '<')
            {
                index--;
            }

            beginIndex = index;

            while (responseContent[index] != '>')
            {
                index++;
            }

            domHTML = responseContent.Substring(beginIndex, index - beginIndex) + "/>";
            dom = XDocument.Parse(domHTML);
            string loginAction = "https://reserve.apple.com" + dom.Root.Attribute("action").Value;

            List<string> usernameAndPasswordIds = new List<string>() { "id=\"appleid\"", "id=\"password\"" };
            string loginPostData = string.Empty;
            foreach (var item in usernameAndPasswordIds)
            {
                index = responseContent.IndexOf(item);
                while (responseContent[index] != '<')
                {
                    index--;
                }

                beginIndex = index;

                while (responseContent[index] != '>')
                {
                    index++;
                }

                domHTML = responseContent.Substring(beginIndex, index - beginIndex + 1);
                dom = XDocument.Parse(domHTML);
                string value = string.Empty;
                if (item == "id=\"appleid\"")
                {
                    value = ConfigHelper.AppleID;
                }
                else
                {
                    value = ConfigHelper.Password;
                }
                loginPostData = loginPostData + dom.Root.Attribute("name").Value + "=" + HttpUtility.UrlEncode(value) + "&";
            }

            index = responseContent.IndexOf("id=\"fwdButtonC\"");
            while (responseContent[index] != '<')
            {
                index--;
            }
            index--;
            while (responseContent[index] != '<')
            {
                index--;
            }

            beginIndex = index;

            while (responseContent[index] != '>')
            {
                index++;
            }

            domHTML = responseContent.Substring(beginIndex, index - beginIndex) + "/>";
            dom = XDocument.Parse(domHTML);
            loginPostData = loginPostData + dom.Root.Attribute("name").Value + "=true";


            RequestContext context = new RequestContext();
            context.RequestUrl = loginAction;
            context.AllowAutoRedirect = false;
            context.Method = "POST";
            context.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
            context.ContentType = "application/x-www-form-urlencoded";
            context.PostData = loginPostData;
            context.Headers.Add("Accept-Encoding", "gzip,deflate,sdch");
            context.Headers.Add("Accept-Language", "en-US,en;q=0.8");
            context.Headers.Add("Cookie", this.cookie);

            ResponseContext response = Helper.GetResponse(context);

            if (response.StatusCode != HttpStatusCode.OK)
            {
                if (response.StatusCode != HttpStatusCode.Redirect || response.Headers.Get("location").Contains("/WebObjects/ProductReservation.woa/wo") == false)
                {
                    throw new Exception();
                }
            }

            bool isTimeout = Helper.CheckSessionTimeout(this.cookie, response.Headers.Get("set-cookie"));
            if (isTimeout == true)
            {
                throw new TimeoutException();
            }

            string cookieString = response.Headers.Get("set-cookie");
            this.cookie = this.cookie + "; " + Helper.GetCookie(cookieString, new List<string>() { "ds01", "DefaultAppleID" });

            if (response.StatusCode == HttpStatusCode.Redirect)
            {
                context = new RequestContext();
                context.RequestUrl = response.Headers.Get("location");
                context.AllowAutoRedirect = false;
                context.Method = "GET";
                context.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
                context.Headers.Add("Accept-Encoding", "gzip,deflate,sdch");
                context.Headers.Add("Accept-Language", "en-US,en;q=0.8");
                context.Headers.Add("Cookie", this.cookie);

                response = Helper.GetResponse(context);
                if (response.StatusCode != HttpStatusCode.OK)
                {
                    throw new Exception();
                }
                isTimeout = Helper.CheckSessionTimeout(this.cookie, response.Headers.Get("set-cookie"));
                if (isTimeout == true)
                {
                    throw new TimeoutException();
                }
            }

            return response.Content;
        }

        public static string[] PickupDateStep(string cookie)
        {
            RequestContext context = new RequestContext();
            context.RequestUrl = "http://reserve.apple.com/WebObjects/ProductReservation.woa/wa/GianduiaAction/fetchPickupDateTimeDetail";
            context.AllowAutoRedirect = false;
            context.Method = "POST";
            context.Accept = "*/*";
            context.ContentType = "application/x-www-form-urlencoded";
            context.PostData = string.Format("lang=en&country={0}", ConfigHelper.CurrentCountry);
            context.Headers.Add("Accept-Encoding", "gzip,deflate,sdch");
            context.Headers.Add("Accept-Language", "en-US,en;q=0.8");
            context.Headers.Add("Cookie", cookie);

            ResponseContext response = Helper.GetResponse(context);
            if (response.StatusCode != HttpStatusCode.OK)
            {
                throw new Exception();
            }
            bool isTimeout = Helper.CheckSessionTimeout(cookie, response.Headers.Get("set-cookie"));
            if (isTimeout == true)
            {
                throw new TimeoutException();
            }

            string responseContent = response.Content;

            int index;
            int beginIndex;
            int nextSearchIndex;
            int searchEndIndex;

            index = responseContent.IndexOf("timeslot :");
            if (index == -1)
            {
                throw new Exception();
            }

            while (responseContent.Substring(index).StartsWith("timestamp") == false)
            {
                index--;
            }
            while (responseContent[index] != '\'')
            {
                index++;
            }
            index++;
            beginIndex = index;
            while (responseContent[index] != '\'')
            {
                index++;
            }
            string timestamp = responseContent.Substring(beginIndex, index - beginIndex);

            while (responseContent.Substring(index).StartsWith("showPickupTimeSlots") == false)
            {
                index++;
            }
            searchEndIndex = index;

            List<string[]> times = new List<string[]>();
            nextSearchIndex = responseContent.IndexOf("timeslot :");
            while (true)
            {
                index = responseContent.IndexOf("timeslot :", nextSearchIndex);
                if (index == -1 || index > searchEndIndex)
                {
                    break;
                }

                while (responseContent[index] != '\'')
                {
                    index++;
                }
                index++;
                beginIndex = index;
                while (responseContent[index] != '\'')
                {
                    index++;
                }
                nextSearchIndex = index;
                string time = responseContent.Substring(beginIndex, index - beginIndex);

                while (responseContent.Substring(index).StartsWith("x-coredata:") == false)
                {
                    index--;
                }
                beginIndex = index;
                while (responseContent[index] != '\'')
                {
                    index++;
                }
                string timeUrl = responseContent.Substring(beginIndex, index - beginIndex);
                times.Add(new string[2] { time, timeUrl });
            }

            string pickupTime = null;
            foreach (var item in times)
            {
                DateTimeOffset wantedTime = DateTimeOffset.Parse("3:57 PM");
                string[] timeRange = item[0].Split('-');
                DateTimeOffset maxTime;
                if (timeRange.Length == 1)
                {
                    maxTime = DateTimeOffset.Parse(timeRange[0]);
                }
                else
                {
                    maxTime = DateTimeOffset.Parse(timeRange[1]);
                }
                if (wantedTime < maxTime)
                {
                    pickupTime = item[1];
                    break;
                }
            }

            if (pickupTime == null)
            {
                pickupTime = times.Last()[1];
            }

            return new string[2] { timestamp, pickupTime };
        }

        private void ConfirmStep(string responseContent, string[] timeAndMark)
        {
            int index;
            int beginIndex;
            string domHTML;
            XDocument dom;

            List<string> confirmIds = new List<string>() { "id=\"selectedDateValue\"", "id=\"selectedTimeValue\"", "id=\"selectedPickupStore\"", "id=\"showDates\"", "id=\"govtIDCheckEnabled\"", "id=\"selectedGovtIDValue\"", "id=\"captchaTextEntered\"", "id=\"userSelectedDateValue\"", "id=\"userSelectedDateValueOne\"", "id=\"userSelectedDateValueTwo\"" };
            string tempConfirmPostData = string.Empty;
            bool needGovernmentID = true;
            foreach (var item in confirmIds)
            {
                index = responseContent.IndexOf(item);
                while (responseContent[index] != '<')
                {
                    index--;
                }

                beginIndex = index;

                while (responseContent[index] != '>')
                {
                    index++;
                }

                domHTML = responseContent.Substring(beginIndex, index - beginIndex + 1);
                dom = XDocument.Parse(domHTML);
                string value = string.Empty;
                switch (item)
                {
                    case "id=\"selectedTimeValue\"":
                        value = timeAndMark[1];
                        break;
                    case "id=\"userSelectedDateValueOne\"":
                        value = timeAndMark[0];
                        break;
                    case "id=\"selectedGovtIDValue\"":
                        if (needGovernmentID == true)
                        {
                            value = ConfigHelper.GovernmentID;
                        }
                        break;
                    default:
                        if (dom.Root.Attribute("value") != null)
                        {
                            value = dom.Root.Attribute("value").Value;
                        }
                        if (item == "id=\"govtIDCheckEnabled\"")
                        {
                            if (value == "N")
                            {
                                needGovernmentID = false;
                            }
                        }
                        break;
                }
                tempConfirmPostData = tempConfirmPostData + dom.Root.Attribute("name").Value + "=" + HttpUtility.UrlEncode(value) + "&";
            }

            index = responseContent.IndexOf("id=\"fwdButtonC\"");
            while (responseContent[index] != '<')
            {
                index--;
            }
            index--;
            while (responseContent[index] != '<')
            {
                index--;
            }

            beginIndex = index;

            while (responseContent[index] != '>')
            {
                index++;
            }

            domHTML = responseContent.Substring(beginIndex, index - beginIndex) + "/>";
            dom = XDocument.Parse(domHTML);

            this.confirmPostData = tempConfirmPostData + dom.Root.Attribute("name").Value + "=true";

            index = responseContent.IndexOf("id=\"TheForm\"");
            while (responseContent[index] != '<')
            {
                index--;
            }

            beginIndex = index;

            while (responseContent[index] != '>')
            {
                index++;
            }

            domHTML = responseContent.Substring(beginIndex, index - beginIndex) + "/>";
            dom = XDocument.Parse(domHTML);
            this.confirmAction = "http://reserve.apple.com" + dom.Root.Attribute("action").Value;

            List<Thread> confirmThreads = new List<Thread>();
            for (int i = 0; i < ConfigHelper.ConfirmConcurrent; i++)
            {
                Thread thread = new Thread(DoConfirm, 512000);
                thread.Start();
                confirmThreads.Add(thread);
            }

            foreach (var item in confirmThreads)
            {
                item.Join();
            }
        }

        private void DoConfirm()
        {
            while (true)
            {
                RequestContext context = new RequestContext();
                context.RequestUrl = this.confirmAction;
                context.AllowAutoRedirect = false;
                context.Method = "POST";
                context.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
                context.ContentType = "application/x-www-form-urlencoded";
                context.PostData = this.confirmPostData;
                context.Headers.Add("Accept-Encoding", "gzip,deflate,sdch");
                context.Headers.Add("Accept-Language", "en-US,en;q=0.8");
                context.Headers.Add("Cookie", this.cookie);

                ResponseContext response = Helper.GetResponse(context);
                if (response.StatusCode == HttpStatusCode.OK)
                {
                    if (response.Headers.Get("set-cookie").Contains("wosid=;") == true)
                    {
                        AutoClickManager.GotIt();
                    }
                    break;
                }
            }
        }

        private void KeepSeesionAlive()
        {
            RequestContext context = new RequestContext();
            context.RequestUrl = this.ContextForCheck.Url;
            context.AllowAutoRedirect = false;
            context.Method = "POST";
            context.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
            context.ContentType = "application/x-www-form-urlencoded";
            context.PostData = this.ContextForCheck.PostData;
            context.Headers.Add("Accept-Encoding", "gzip,deflate,sdch");
            context.Headers.Add("Accept-Language", "en-US,en;q=0.8");
            context.Headers.Add("Cookie", this.ContextForCheck.Cookie + "; geo=CN");

            ResponseContext response = Helper.GetResponse(context);
            if (response.StatusCode != HttpStatusCode.OK)
            {
                throw new Exception();
            }
            bool isTimeout = Helper.CheckSessionTimeout(this.ContextForCheck.Cookie, response.Headers.Get("set-cookie"));
            if (isTimeout == true)
            {
                throw new TimeoutException();
            }
        }

        public void DoWork()
        {
            AutoClickManager.InitialDoor.Wait();

            while (true)
            {
                this.cookie = string.Empty;
                this.ContextForCheck = null;

                string responseContent;

                try
                {
                    while (true)
                    {
                        try
                        {
                            responseContent = InitialStep();
                            break;
                        }
                        catch (Exception ex)
                        {
                        }
                    }

                    while (true)
                    {
                        try
                        {
                            SelectStoreStep(responseContent);
                            break;
                        }
                        catch (Exception ex)
                        {
                            if (ex is TimeoutException)
                            {
                                throw;
                            }
                        }
                    }

                    int reservedCount = 0;
                    while (true)
                    {
                        try
                        {
                            AddToCartStep();
                            reservedCount++;
                            if (reservedCount == ConfigHelper.ReserveCount)
                            {
                                break;
                            }
                        }
                        catch (Exception ex)
                        {
                            if (ex is TimeoutException)
                            {
                                throw;
                            }
                        }
                    }

                    while (true)
                    {
                        try
                        {
                            responseContent = CreateReservationStep();
                            break;
                        }
                        catch (Exception ex)
                        {
                            if (ex is TimeoutException)
                            {
                                throw;
                            }
                        }
                    }

                    while (true)
                    {
                        try
                        {
                            responseContent = CreateReservationRedirectStep(responseContent);
                            break;
                        }
                        catch (Exception ex)
                        {
                            if (ex is TimeoutException)
                            {
                                throw;
                            }
                        }
                    }

                    while (true)
                    {
                        try
                        {
                            responseContent = LoginStep(responseContent);
                            break;
                        }
                        catch (Exception ex)
                        {
                            if (ex is TimeoutException)
                            {
                                throw;
                            }
                        }
                    }

                    string[] timeAndMark = null;
                    if (confirmMode == ConfirmMode.SignalMode)
                    {
                        while (true)
                        {
                            bool isSet = AutoClickDatePicker.PickDateDoor.Wait(ConfigHelper.Sleep);
                            if (isSet == true)
                            {
                                break;
                            }
                            else
                            {
                                while (true)
                                {
                                    try
                                    {
                                        if (AutoClickDatePicker.PickDateDoor.IsSet == true)
                                        {
                                            break;
                                        }
                                        KeepSeesionAlive();
                                        break;
                                    }
                                    catch (Exception ex)
                                    {
                                        if (ex is TimeoutException)
                                        {
                                            throw;
                                        }
                                    }
                                }
                            }
                        }

                        while (true)
                        {
                            bool isSet = false;
                            try
                            {
                                Interlocked.Increment(ref WaitingCheckDoorCount);
                                isSet = AutoClickChecker.CheckDoor.Wait(ConfigHelper.Sleep);
                            }
                            finally
                            {
                                Interlocked.Decrement(ref WaitingCheckDoorCount);
                            }
                            
                            if (isSet == true)
                            {
                                break;
                            }
                            else
                            {
                                while (true)
                                {
                                    try
                                    {
                                        if (AutoClickChecker.CheckDoor.IsSet == true)
                                        {
                                            break;
                                        }
                                        KeepSeesionAlive();
                                        break;
                                    }
                                    catch (Exception ex)
                                    {
                                        if (ex is TimeoutException)
                                        {
                                            throw;
                                        }
                                    }
                                }
                            }
                        }

                        timeAndMark = AutoClickDatePicker.TimeAndMark;
                    }
                    else
                    {
                        while (true)
                        {
                            try
                            {
                                timeAndMark = PickupDateStep(this.cookie);
                                break;
                            }
                            catch (Exception ex)
                            {
                                if (ex is TimeoutException)
                                {
                                    throw;
                                }
                            }
                        }
                    }

                    ConfirmStep(responseContent, timeAndMark);
                }
                catch (Exception ex)
                {
                }
            }
        }
    }
}
